#!/bin/bash

# 脚本功能：自动构建Spring Boot基座项目和插件项目，使用xjar进行加密，并编译Go启动器

# 设置颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 打印带颜色的信息
print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

print_step() {
    echo -e "${BLUE}[STEP]${NC} $1"
}

# 检查命令执行结果
check_result() {
    if [ $? -ne 0 ]; then
        print_error "$1"
        exit 1
    fi
}

# 设置项目路径
PROJECT_ROOT="/home/daoos/IdeaProjects/xjar-plus"
SPRING_PROJECTS="$PROJECT_ROOT/spring-projects"
APP_DIR="$PROJECT_ROOT/app/encrypted"
PLUGINS_DIR="$PROJECT_ROOT/plugins"
RESOURCE_DIR="$APP_DIR/resource"

# 创建必要的目录
print_step "创建必要的目录"
mkdir -p "$RESOURCE_DIR"
mkdir -p "$APP_DIR/plugins"
check_result "无法创建目录"

# 打包基座项目
print_step "打包基座项目"
cd "$SPRING_PROJECTS/base-project"
print_info "清理并打包基座项目..."
mvn clean package -DskipTests
check_result "基座项目打包失败"

# 打包插件A
print_step "打包插件A"
cd "$SPRING_PROJECTS/plugin-a"
print_info "清理并打包插件A..."
mvn clean package -DskipTests
check_result "插件A打包失败"

# 打包插件B
print_step "打包插件B"
cd "$SPRING_PROJECTS/plugin-b"
print_info "清理并打包插件B..."
mvn clean package -DskipTests
check_result "插件B打包失败"

# 复制生成的JAR文件到临时位置
print_step "复制生成的JAR文件到临时位置"
cd "$SPRING_PROJECTS/base-project"
BASE_JAR=$(find target -name "*.jar" -type f | head -n 1)
cp "$BASE_JAR" "$PROJECT_ROOT/base-project.jar"
check_result "无法复制基座项目JAR文件"

cd "$SPRING_PROJECTS/plugin-a"
PLUGIN_A_JAR=$(find target -name "*.jar" -type f | head -n 1)
cp "$PLUGIN_A_JAR" "$PROJECT_ROOT/plugin-a.jar"
check_result "无法复制插件A JAR文件"

cd "$SPRING_PROJECTS/plugin-b"
PLUGIN_B_JAR=$(find target -name "*.jar" -type f | head -n 1)
cp "$PLUGIN_B_JAR" "$PROJECT_ROOT/plugin-b.jar"
check_result "无法复制插件B JAR文件"

print_info "所有项目打包完成！"

# 尝试使用xjar-plus进行加密
print_step "尝试使用xjar-plus进行加密"

# 检查是否有可用的xjar-plus JAR文件
XJAR_AVAILABLE=false
if [ -f "$PROJECT_ROOT/target/classes/io/xjar/XCryptos.class" ]; then
    print_info "使用本地编译的xjar-plus进行加密"
    cd "$PROJECT_ROOT"
    
    # 加密基座项目并生成Go启动器
    print_info "加密基座项目并生成Go启动器"
    java -cp "$PROJECT_ROOT/target/classes" io.xjar.XCryptos encryption \
        -from "$PROJECT_ROOT/base-project.jar" \
        -to "$APP_DIR" \
        -password "xjar" \
        -appName "app.x"
    
    if [ $? -eq 0 ]; then
        print_info "基座项目加密成功"
        XJAR_AVAILABLE=true
    else
        print_warn "基座项目加密失败"
    fi
    
    # 如果xjar可用，继续加密插件
    if [ "$XJAR_AVAILABLE" = true ]; then
        # 加密插件A
        print_info "加密插件A"
        java -cp "$PROJECT_ROOT/target/classes" io.xjar.XCryptos encryption \
            -from "$PROJECT_ROOT/plugin-a.jar" \
            -to "$APP_DIR/plugins" \
            -password "xjar" \
            -appName "plugin-a.x" \
            -plugin
        
        if [ $? -eq 0 ]; then
            print_info "插件A加密成功"
        else
            print_warn "插件A加密失败"
        fi
        
        # 加密插件B
        print_info "加密插件B"
        java -cp "$PROJECT_ROOT/target/classes" io.xjar.XCryptos encryption \
            -from "$PROJECT_ROOT/plugin-b.jar" \
            -to "$APP_DIR/plugins" \
            -password "xjar" \
            -appName "plugin-b.x" \
            -plugin
        
        if [ $? -eq 0 ]; then
            print_info "插件B加密成功"
        else
            print_warn "插件B加密失败"
        fi
    fi
fi

# 如果xjar不可用，使用简化流程
if [ "$XJAR_AVAILABLE" = false ]; then
    print_warn "未找到编译好的xjar-plus，使用简化流程"
    
    # 直接复制基座项目并重命名
    cp "$PROJECT_ROOT/base-project.jar" "$APP_DIR/app.x"
    
    # 直接复制插件并重命名
    cp "$PROJECT_ROOT/plugin-a.jar" "$APP_DIR/plugins/plugin-a.x"
    cp "$PROJECT_ROOT/plugin-b.jar" "$APP_DIR/plugins/plugin-b.x"
    
    # 创建简化版Go启动器
    print_step "创建简化版Go启动器"
    cat > "$APP_DIR/main.go" << 'EOF'
package main

import (
    "fmt"
    "os"
    "os/exec"
    "path/filepath"
    "strings"
)

func main() {
    // 检查命令行参数
    args := os.Args[1:]
    if len(args) > 0 {
        switch args[0] {
        case "add-plugin":
            if len(args) < 2 {
                fmt.Println("Usage: app add-plugin <plugin-file>")
                os.Exit(1)
            }
            if err := addPlugin(args[1]); err != nil {
                fmt.Printf("Failed to add plugin: %v\n", err)
                os.Exit(1)
            }
            fmt.Printf("Plugin %s added successfully\n", args[1])
            return
        case "remove-plugin":
            if len(args) < 2 {
                fmt.Println("Usage: app remove-plugin <plugin-name>")
                os.Exit(1)
            }
            if err := removePlugin(args[1]); err != nil {
                fmt.Printf("Failed to remove plugin: %v\n", err)
                os.Exit(1)
            }
            fmt.Printf("Plugin %s removed successfully\n", args[1])
            return
        case "list-plugins":
            if err := listPlugins(); err != nil {
                fmt.Printf("Failed to list plugins: %v\n", err)
                os.Exit(1)
            }
            return
        }
    }
    
    fmt.Println("XJar Plus Application Launcher")
    
    // 获取当前可执行文件的目录
    exePath, _ := os.Executable()
    exeDir := filepath.Dir(exePath)
    
    // 检查app.x是否存在
    appPath := filepath.Join(exeDir, "app.x")
    if _, err := os.Stat(appPath); os.IsNotExist(err) {
        fmt.Printf("Error: app.x not found at %s\n", appPath)
        os.Exit(1)
    }
    
    // 提取插件
    pluginDir := filepath.Join(exeDir, "plugins")
    if err := extractPlugins(pluginDir); err != nil {
        fmt.Printf("Warning: Failed to extract plugins: %v\n", err)
    }
    
    // 简单运行Java命令
    argsStr := "-jar " + appPath
    cmdArgs := strings.Fields(argsStr)
    cmd := exec.Command("java", cmdArgs...)
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    
    fmt.Println("Starting application...")
    if err := cmd.Run(); err != nil {
        fmt.Printf("Error running application: %v\n", err)
        os.Exit(1)
    }
}

// addPlugin 添加插件
func addPlugin(pluginFile string) error {
    // 获取可执行文件所在目录
    exeDir := filepath.Dir(os.Args[0])
    pluginsDir := filepath.Join(exeDir, "plugins")
    
    // 创建插件目录（如果不存在）
    if err := os.MkdirAll(pluginsDir, os.ModePerm); err != nil {
        return fmt.Errorf("failed to create plugins directory: %v", err)
    }
    
    // 检查插件文件是否存在
    if _, err := os.Stat(pluginFile); os.IsNotExist(err) {
        return fmt.Errorf("plugin file does not exist: %s", pluginFile)
    }
    
    // 获取插件文件名
    pluginName := filepath.Base(pluginFile)
    
    // 检查是否为.x文件
    if filepath.Ext(pluginName) != ".x" {
        return fmt.Errorf("plugin file must have .x extension")
    }
    
    // 复制插件文件到插件目录
    pluginPath := filepath.Join(pluginsDir, pluginName)
    
    // 读取插件文件
    data, err := os.ReadFile(pluginFile)
    if err != nil {
        return fmt.Errorf("failed to read plugin file: %v", err)
    }
    
    // 写入插件文件
    if err := os.WriteFile(pluginPath, data, os.ModePerm); err != nil {
        return fmt.Errorf("failed to write plugin file: %v", err)
    }
    
    return nil
}

// removePlugin 移除插件
func removePlugin(pluginName string) error {
    // 获取可执行文件所在目录
    exeDir := filepath.Dir(os.Args[0])
    pluginsDir := filepath.Join(exeDir, "plugins")
    
    // 构建插件文件路径
    pluginPath := filepath.Join(pluginsDir, pluginName)
    
    // 检查插件文件是否存在
    if _, err := os.Stat(pluginPath); os.IsNotExist(err) {
        return fmt.Errorf("plugin does not exist: %s", pluginName)
    }
    
    // 删除插件文件
    if err := os.Remove(pluginPath); err != nil {
        return fmt.Errorf("failed to remove plugin: %v", err)
    }
    
    return nil
}

// listPlugins 列出所有插件
func listPlugins() error {
    // 获取可执行文件所在目录
    exeDir := filepath.Dir(os.Args[0])
    pluginsDir := filepath.Join(exeDir, "plugins")
    
    // 检查插件目录是否存在
    if _, err := os.Stat(pluginsDir); os.IsNotExist(err) {
        fmt.Println("No plugins directory found")
        return nil
    }
    
    // 读取插件目录
    entries, err := os.ReadDir(pluginsDir)
    if err != nil {
        return fmt.Errorf("failed to read plugins directory: %v", err)
    }
    
    fmt.Println("Installed plugins:")
    for _, entry := range entries {
        if entry.IsDir() {
            continue
        }
        
        // 只显示.x文件
        if filepath.Ext(entry.Name()) == ".x" {
            info, _ := entry.Info()
            fmt.Printf("- %s (size: %d bytes)\n", entry.Name(), info.Size())
        }
    }
    
    return nil
}

// extractPlugins 模拟插件提取功能
func extractPlugins(pluginPath string) error {
    fmt.Printf("Extracting plugins to: %s\n", pluginPath)
    
    // 创建插件目录
    if err := os.MkdirAll(pluginPath, os.ModePerm); err != nil {
        return fmt.Errorf("failed to create plugin directory: %v", err)
    }
    
    // 在实际应用中，这里会从嵌入的资源中提取插件
    // 但在简化版中，我们只是确保目录存在
    fmt.Println("Plugin extraction complete")
    return nil
}
EOF
fi

# 编译Go启动器
print_step "编译Go启动器"

# 检查Go是否安装
if command -v go &> /dev/null; then
    print_info "Go已安装，开始编译..."
    
    # 检查是否存在main.go文件
    if [ -f "$APP_DIR/main.go" ]; then
        # 编译Go启动器
        cd "$APP_DIR"
        go build -o app main.go
        if [ $? -eq 0 ]; then
            print_info "Go启动器编译成功"
        else
            print_error "Go启动器编译失败"
        fi
    else
        print_warn "未找到main.go文件，跳过Go启动器编译"
    fi
else
    print_warn "未安装Go，跳过Go启动器编译"
fi

print_info "构建、加密和编译流程完成！"
if [ "$XJAR_AVAILABLE" = true ]; then
    print_info "基座项目和Go启动器位于: $APP_DIR/"
else
    print_info "基座项目位于: $APP_DIR/app.x"
fi
print_info "插件位于: $APP_DIR/plugins/"

print_info "使用说明:"
print_info "  启动应用: $APP_DIR/app"
print_info "  添加插件: $APP_DIR/app add-plugin <plugin-file>"
print_info "  移除插件: $APP_DIR/app remove-plugin <plugin-name>"
print_info "  列出插件: $APP_DIR/app list-plugins"